<?php

namespace app\common;
use app\api\model\Member as MemberModel;
use app\api\model\BaseConfig as BaseConfigModel;
use app\common\model\BlockchainOrder as BlockchainOrderModel;
use app\common\model\MemberCurrency as MemberCurrencyModel;
use app\common\model\MemberLevel as MemberLevelModel;
use app\common\model\TaskLog;
use app\common\model\UserMoneyLog;
use app\common\model\UserMoneyLog as UserMoneyLogModel;
use app\common\model\TotalTime  as TotalTimeModel;
use think\facade\Db;

class common
{
    /**
     * 根据key 获取币种
     * @param $key
     */
    public static function key_currency($key){
        $name = 'usdt';
        switch ($key){
            case 1: $name = 'usdt'; //USDt
                break;
            case 22: $name = 'kr';  //KR
                break;
            case 23: $name = 'lp';  //lp
                break;

        }
        return $name;
    }

    //查询当前用户的13矩阵图 3**3
    public static function member_matrix($mid){
        $position = [
            'position'   =>  time(),
            'username'   =>  '',
            'level_id'   =>  '',
            'status'   =>  '',
            'id'   =>  '',
        ];
        if(!is_array($mid)){
            $member = MemberModel::getDetails($mid);
            if(empty($member)) return false;
            if(!empty($member['position'])){
                $data = [
                    '0'=>[
                        'id'    =>  $mid,
                        'username'=>$member['username'],
                        'position'  =>  $member['position'],
                        'level_id'  =>  $member['level_id'],
                        'status'  =>  $member['status'],
                    ],
                    '1'=>MemberModel::position($member['position']*3-1),
                    '2'=>MemberModel::position($member['position']*3),
                    '3'=>MemberModel::position($member['position']*3+1),

                    '4'=>MemberModel::position(($member['position']*3-1)*3-1),
                    '5'=>MemberModel::position(($member['position']*3-1)*3),
                    '6'=>MemberModel::position(($member['position']*3-1)*3+1),

                    '7'=>MemberModel::position($member['position']*3*3-1),
                    '8'=>MemberModel::position($member['position']*3*3),
                    '9'=>MemberModel::position($member['position']*3*3+1),

                    '10'=>MemberModel::position(($member['position']*3+1)*3-1),
                    '11'=>MemberModel::position(($member['position']*3+1)*3),
                    '12'=>MemberModel::position(($member['position']*3+1)*3+1),
                ];
            }else{

                $data = [
                    '0'=>[
                        'id'    =>  $mid,
                        'username'=>$member['username'],
                        'position'  =>  $member['position'],
                        'level_id'  =>  $member['level_id'],
                        'status'  =>  $member['status'],
                    ],
                    '1'=>$position,
                    '2'=>$position,
                    '3'=>$position,
                    '4'=>$position,
                    '5'=>$position,
                    '6'=>$position,
                    '7'=>$position,
                    '8'=>$position,
                    '9'=>$position,
                    '10'=>$position,
                    '11'=>$position,
                    '12'=>$position
                ];
            }
        }else{
            $data = [];
            foreach ($mid as $k => $v){
                $member = MemberModel::getDetails($v);
                if(!empty($member['position'])) {
                    $data[$k] = [
                        '0' => [
                            'id' => $v,
                            'username' => $member['username'],
                            'position' => $member['position'],
                            'level_id' => $member['level_id'],
                            'status' => $member['status'],
                        ],

                        '1' => MemberModel::position($member['position'] * 3 - 1),
                        '2' => MemberModel::position($member['position'] * 3),
                        '3' => MemberModel::position($member['position'] * 3 + 1),

                        '4' => MemberModel::position(($member['position'] * 3 - 1) * 3 - 1),
                        '5' => MemberModel::position(($member['position'] * 3 - 1) * 3),
                        '6' => MemberModel::position(($member['position'] * 3 - 1) * 3 + 1),

                        '7' => MemberModel::position($member['position'] * 3 * 3 - 1),
                        '8' => MemberModel::position($member['position'] * 3 * 3),
                        '9' => MemberModel::position($member['position'] * 3 * 3 + 1),

                        '10' => MemberModel::position(($member['position'] * 3 + 1) * 3 - 1),
                        '11' => MemberModel::position(($member['position'] * 3 + 1) * 3),
                        '12' => MemberModel::position(($member['position'] * 3 + 1) * 3 + 1),
                    ];
                }else{
                    $data[$k] = [
                        '0'=>[
                            'id'    =>  $mid,
                            'username'=>$member['username'],
                            'position'  =>  $member['position'],
                            'level_id'  =>  $member['level_id'],
                            'status'  =>  $member['status'],
                        ],
                        '1'=>$position,
                        '2'=>$position,
                        '3'=>$position,
                        '4'=>$position,
                        '5'=>$position,
                        '6'=>$position,
                        '7'=>$position,
                        '8'=>$position,
                        '9'=>$position,
                        '10'=>$position,
                        '11'=>$position,
                        '12'=>$position
                    ];
                }
            }
        }

        return $data;
    }

    /**
     * 自动滑落匹配
     * @param $mid  用户ID
     * @param $type 1:正常矩阵图 2：非正常矩阵图
     * @return array|false
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function member_matrix_matching($mid,$type = 1){
        if(!is_array($mid)){
            $member = MemberModel::getDetails($mid);
            if(empty($member)) return false;
            if(empty($member['position'])) $member = MemberModel::getDetails(1)->toArray();
            $data = [
                '0'=>[
                    'id'    =>  $mid,
                    'username'=>$member['username'],
                    'position'  =>  $member['position'],
                    'level_id'  =>  $member['level_id'],
                    'status'  =>  $member['status'],
                ],
                '1'=>MemberModel::position($member['position']*3-1),
                '2'=>MemberModel::position($member['position']*3),
                '3'=>MemberModel::position($member['position']*3+1),
            ];

            if($type == 1){
                $data[4] = MemberModel::position(($member['position']*3-1)*3-1);
                $data[5] = MemberModel::position($member['position']*3*3-1);
                $data[6] = MemberModel::position(($member['position']*3+1)*3-1);

                $data[7] = MemberModel::position(($member['position']*3-1)*3);
                $data[8] = MemberModel::position($member['position']*3*3);
                $data[9] = MemberModel::position(($member['position']*3+1)*3);

                $data[10] = MemberModel::position(($member['position']*3-1)*3+1);
                $data[11] = MemberModel::position($member['position']*3*3+1);
                $data[12] = MemberModel::position(($member['position']*3+1)*3+1);
            }

        }else{

            $data = [];
            foreach ($mid as $k => $v){
                $member = MemberModel::getDetails($v);

                $data[$k] = [
                    '0'=>[
                        'id'    =>  $v,
                        'username'=>$member['username'],
                        'position'  =>  $member['position'],
                        'level_id'  =>  $member['level_id'],
                        'status'  =>  $member['status'],
                    ],

                    '1'=>MemberModel::position($member['position']*3-1),
                    '2'=>MemberModel::position($member['position']*3),
                    '3'=>MemberModel::position($member['position']*3+1),
                ];

                if($type == 1){
                    $data[4] = MemberModel::position(($member['position']*3-1)*3-1);
                    $data[5] = MemberModel::position($member['position']*3*3-1);
                    $data[6] = MemberModel::position(($member['position']*3+1)*3-1);

                    $data[7] = MemberModel::position(($member['position']*3-1)*3);
                    $data[8] = MemberModel::position($member['position']*3*3);
                    $data[9] = MemberModel::position(($member['position']*3+1)*3);

                    $data[10] = MemberModel::position(($member['position']*3-1)*3+1);
                    $data[11] = MemberModel::position($member['position']*3*3+1);
                    $data[12] = MemberModel::position(($member['position']*3+1)*3+1);
                }

            }
        }

        return $data;
    }

    //3**3矩阵 自动下滑
    public static function downward($mid,$ceng = 1){
        $matrix_list = [];
        if($ceng == 1){ //最高一层
            $matrix = self::member_matrix_matching($mid);
            foreach ($matrix as $k => $v){
                if(empty($v['id'])){
                    return $v['position'];
                }else{
                    //排除
                    if($k!=1&&$k!=2&&$k!=3) $matrix_list[] = $v['id'];
                }
            }
        }else{

            $matrix = self::member_matrix_matching($mid,2);
            $weizhi  = [];
            foreach ($matrix as $k => $v){
                foreach ($v as $ks => $vs) {
                    $weizhi[$vs['position']] = $vs;
                }
            }
            ksort($weizhi);

            $matrix = [];
            foreach ($weizhi as $k => $v){
                $matrix[] = $v;
            }

            foreach ($matrix as $k => $v) {

                if (($v['position']+1) % 3 == 0) {
                    if (empty($v['id'])) {
                        return $v['position'];
                    } else {
                        //排除
                        if ($k != 1 && $k != 2 && $k != 3) $matrix_list[] = $v['id'];
                    }
                }
            }

            foreach ($matrix as $k => $v) {
                if(($v['position'])%3 == 0) {
                    if (empty($v['id'])) {
                        return $v['position'];
                    } else {
                        //排除
                        if ($k != 1 && $k != 2 && $k != 3) $matrix_list[] = $v['id'];
                    }
                }
            }

            foreach ($matrix as $k => $v) {
                if(($v['position']-1)%3 == 0) {
                    if (empty($v['id'])) {
                        return $v['position'];
                    } else {
                        //排除
                        if ($k != 1 && $k != 2 && $k != 3) $matrix_list[] = $v['id'];
                    }
                }
            }
        }

        if(!empty($matrix_list)){
            $ceng += 1;
            $position = self::downward($matrix_list,$ceng);
            return $position;
        }
    }

    /**
     * 查询已支付 USDT
     * @throws \GuzzleHttp\Exception\GuzzleException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function paid_payStatus(){
        //查询一天内未支付的USDT订单
        $list = BlockchainOrderModel::getList([['status','=',1],['currency','=',1],['add_time', '>', time()-81600]],1,100);
        
        if(!empty($list['data'])){
            //执行支付确认
            self::bscscan_paid_pay($list['data']);
        }
    }

    /**
     * 币安USDT查询
     * @param $txhash
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function bscscan_paid_pay($txhash_list){
        $key = BaseConfigModel::config_data('usdt_key');//交易apiKey
        $usdt_contract = BaseConfigModel::config_data('usdt_contract');//合约地址
        $usdt_address = BaseConfigModel::config_data('usdt_address');//收款地址
        $client = new \GuzzleHttp\Client();

        //测试网
//        $url = 'https://api-testnet.bscscan.com/api?module=account&action=tokentx&contractaddress='.$usdt_contract.'&address='.$usdt_address.'&page=1&offset=10&startblock=0&endblock=999999999&sort=asc&apikey='.$key;
        //正式网
//        $url = 'https://api.bscscan.com/api?module=account&action=tokentx&contractaddress='.$usdt_contract.'&address='.$usdt_address.'&page=1&offset=10&startblock=0&endblock=999999999&sort=asc&apikey='.$key;
        $url = 'https://api.bscscan.com/api?module=account&action=tokentx&contractaddress='.$usdt_contract.'&address='.$usdt_address.'&page=1&offset=30&startblock=0&endblock=999999999&sort=desc&apikey='.$key;
        
        //币安交易记录
        $response = $client->request('GET', $url, [
            'headers' => [
                'accept' => 'application/json',
            ],
        ]);
        //json 订单 转数组
        $orderInfo = json_decode($response->getBody(),true);

        Db::startTrans();
        try {

            $order_result = array_column($orderInfo['result'],'hash');
            //删除未支付的订单
            foreach ($txhash_list as $k => $v){
                //判断是否存在该订单 , 不存在则删除
                if(!in_array($v['txhash'],$order_result)) unset($txhash_list[$k]);
                
            }
            
            //判断有已确认的支付信息
            if(!empty($txhash_list)){
                foreach ($txhash_list as $v){   //循环平台订单
                    foreach ($orderInfo['result'] as $va){  //循环链订单
                        
                        if($v['txhash'] == $va['hash']){    //判断哈希值
                            //计算支付数量
                            $va['money'] = bcdiv($va['value'],1000000000000000000,2);
                            //判断金额是否对得上         //执行充值成功操作
                            
                            if($va['money'] == $v['money']){
                                 BlockchainOrderModel::getStatus($v,$va);
                                BlockchainOrderModel::upstatus($v['id'],$va['from']);
                            }
                        }
                    }
                }

            }

            Db::commit();
            TaskLog::add('币安USDT充值',1,json_encode($txhash_list),'释放成功');
            return true;
        } catch (\Exception $exception) {
            Db::rollback();
            TaskLog::add('币安USDT充值',2,json_encode($txhash_list),'充值失败');
            return false;
        }
    }

    /**
     * 递减式释放矿机
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function Diminishing_release(){

        //获取兑换比例
        $client = new \GuzzleHttp\Client();
        $time = time();
        $response = $client->request('GET', env('HEYUEURL_EMPOWER').'getAmountkfOut', [
            'headers' => [
                'accept'=>'application/json',
                'content-type'=>'application/json',
                'sign'  =>  md5(env('HEADER_SIGN').'time:'.$time),
                'header_time'   =>  $time
            ]
        ]);
        $getAmountkfOut_data = json_decode($response->getBody(),true);

        $bili = 3000;
        if(is_array($getAmountkfOut_data)){
            //失败则默认3000
            if($getAmountkfOut_data['code'] == 1) $bili = $getAmountkfOut_data['data'];
        }

        //获取当前剩余LP总底池
        $release_lp = BaseConfigModel::config_data('release_lp');
        //本次总释放
        $new_releae = bcmul($release_lp,0.005,16);

        $member_currency_list = MemberCurrencyModel::where('money','>',0)->where('cid',23)->field('mid,money')->select()->toArray();
        $total_power = MemberCurrencyModel::where('cid',23)->sum('money');
        //一份
        $single_releae = bcdiv($new_releae,$total_power,23);

        Db::startTrans();
        try {
            foreach ($member_currency_list as $v){
                $money = bcmul($single_releae,$v['money'],8);
                //计算要扣除的LP
                $lp = bcdiv($money,$bili,8);
                //扣除对应算力的LP
                $lp_state = UserMoneyLogModel::change($v['mid'],'LP',-$lp,'Mining machine output','','每日矿机产出扣除对应算力');
                //奖励KR
                if($lp_state) UserMoneyLogModel::change($v['mid'],'KR',$money,'Mining machine output','','每日矿机产出',2);
            }
            //扣除已释放的LP
            BaseConfigModel::where('name','release_lp')->update(['data'=>bcsub($release_lp,$new_releae,8)]);

            Db::commit();
            echo '释放完成！';
        } catch (\Exception $exception) {
            Db::rollback();
            echo '释放失败！';
        }


    }

    /**
     * 根据位置上层用户
     * @param $position 位置
     * @return array|false
     */
    public static function superior_matrix($position){
        if(($position+1)%3 == 0){
            $new_position = bcdiv($position+1,3);
        }else{
            if($position%3 == 0){
                $new_position = bcdiv($position,3);
            }else{
                $new_position = bcdiv($position-1,3);
            }
        }
        $member = false;
        if($new_position > 0) $member = MemberModel::position($new_position);
        return $member;
    }

    /**
     * 矿机等级极差分红
     * @param $mid  用户ID
     * @param $money    用户金额
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function maxtrix_mlevel($mid,$money){
       $team_range_status  = BaseConfigModel::config_data('team_range_status');
       if($team_range_status == 1){ //开启矿机团队分红
            $level_list = MemberLevelModel::getMemberList();
            $level = [];
            $max = 0;
            foreach ($level_list as $v){    //循环用户等级
                $level[$v['id']] = $v;
                if($max < $v['level']) $max = $v['level'];
            }

            //查询用户详情
            $member = MemberModel::getDetails($mid);
            if(!empty($member['pid'])){
                //递归团队
                $arr = self::recursion_team_maxtrix($member['pid'],$level,$member['level_id'],$max);
            }

            if(!empty($arr)){   //发放见点奖
                foreach ($arr as $v){
                    $lcc = bcmul($money,$v['matrix_team']/100,2);
                    UserMoneyLogModel::change($v['id'],'lcc',$lcc,'Mining machine insight award','','矿机见点奖励：'.$lcc);
                }
            }
       }
    }

    /**
     * 递归团队
     * @param $mid  用户ID
     * @param $level    会员等级列表
     * @param $level_id 上个会员等级ID
     * @param $max  最大等级
     * @param array $arr    奖励会员数组
     * @return array|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private static function recursion_team_maxtrix($mid,$level,$level_id,$max,$arr = [])
    {
        //查询用户详情
        $member = MemberModel::getDetails($mid);

        if (empty($member)) { //判断用户是否存在
            return $arr;
        }

        //判断用户等级
        if ($level[$member['level_id']]['level'] > $level[$level_id]['level']) { //最新用户大于当前用户
            $arr[$mid] = [
                'id' => $mid,
                'matrix_team' => $level[$member['level_id']]['matrix_team']
            ];

            //用户等级ID
            $level_id = $member['level_id'];

            //最高等级 或 不存在上级ID
            if ($level[$member['level_id']]['level'] == $max || empty($member['pid'])) {
                return $arr;
            }

        }

        $list = self::recursion_team_maxtrix($member['pid'], $level, $level_id, $max, $arr);

        foreach ($list as $k => $v) {
            $arr[$k] = $v;
        }

        return $arr;
    }

    /**
     * Trc20外部请求触发功能
     */
    public static function trc20_request($url_name,$key = ''){
        $url = 'http://trc.xinhuoio.com/api/task/'.$url_name.'?secret_key='.$key;
        $client = new \GuzzleHttp\Client();
        $response = $client->request('GET', $url, [
            'headers' => [
                'accept' => 'application/json',
            ],
        ]);
        $data = json_decode($response->getBody(),true);
        return $data;
    }

    /**
     * 转换数字为简短形式
     * @param $n int 要转换的数字
     * @param $precision int 精度
     */
    public static function shortenNumber($n, $precision = 1)
    {
        if ($n < 1e+3) {
            $out = number_format($n);
        } else if ($n < 1e+6) {
            $out = number_format($n / 1e+3, $precision) . 'k';
        } else if ($n < 1e+9) {
            $out = number_format($n / 1e+6, $precision) . 'm';
        } else if ($n < 1e+12) {
            $out = number_format($n / 1e+9, $precision) . 'b';
        }

        return $out;
    }

    /**
     * 创建txt文件并写入日志内容
     * @param $name 目录
     * @param $new_data 内容
     */
    public static function RobotIdFileWrite($name,$new_data)
    {
        $file = $_SERVER['DOCUMENT_ROOT']."/".$name."/".date('Ymd',time());

        if(!file_exists($file)) $res=mkdir(iconv("UTF-8", "GBK", $file),0777,true);

        $fp = fopen($file. "/".date('H-i-s',time()).".txt","wb");
        fwrite($fp,$new_data);
        fclose($fp);
    }

    //读取txt文件
    public static function RobotIdFileRed($url)
    {
        $file_path = $_SERVER['DOCUMENT_ROOT']."/".$url;
        if(file_exists($file_path)) {
            $fp = fopen($file_path, "r");
            $str = fread($fp, filesize($file_path));//指定读取大小，这里把整个文件内容读取出来
            return $str = str_replace("\r\n", "<br />", $str);
        }
        return '';
    }

    /**
     * 升级分红
     * @param $mid  用户ID
     * @param $lid 用户等级ID
     * @param $money    升级所用金额
     * @param $u_money    全网分享的U
     */
    public static function upgrade_dividend($mid,$lid,$money,$usdt_money){
        // 启动事务
        Db::startTrans();
        try {
        
            $member = MemberModel::where('id',$mid)->find();
            //获取用户三星矩阵上级用户
            $juzhen_member = MemberModel::matrixLevelSuperior($member['position'],$lid);
            foreach ($juzhen_member as $v){
                $mem = MemberModel::where('id',$v['id'])->find();
                 //直推烧伤算法：上级level_id>当前会员level_id，发放直推奖 KR
                if($mem==null||$mem['level_id']<$member['level_id']-1){//这里的member.level_id是外层函数升级过的，所以是大于等于-1
                    continue;
                }

                //发放 - 矩阵团队10层KR
                UserMoneyLogModel::change($v['id'],'KR',bcmul(bcdiv($money,3,8),0.1,8),'Community dividends','','社区分红');
                //MemberModel::where('id',$v['id'])->update(['power'=>bcadd($v['power'],bcmul($usdt_money,0.02,8),4)]);
                //发放流动性算力
                UserMoneyLogModel::change($v['id'],'LP',bcmul($usdt_money,0.02,8),'Community dividends','','社区分红');
            }
            
            //全网均分8%的U
            $u_money = bcmul($usdt_money,0.08,8);
            if($u_money > 0){   //时时分发
                $power = MemberModel::where('power','>',0)->sum('power');
                if($power > 0){
                    //计算每一份所得数量
                    $one_power = bcdiv($u_money,$power,16);
                    //查询全网用户
                    $wmember = MemberModel::where('power','>',0)->field('id,power')->select();
                    
                    foreach ($wmember as $vpower){
                        //计算我所得数量
                        $umoney = bcmul($vpower['power'],$one_power,8);
                        if($vpower['power'] < $umoney) $umoney = $vpower['power'];
                        UserMoneyLogModel::change($vpower['id'],'USDT',$umoney,'Whole network USDT dividend',$mid,'全网USDT分红');
                        $mpower = bcsub($vpower['power'],$umoney,8);
                        MemberModel::where('id',$vpower['id'])->update(['power'=>$mpower]);
                    }
                }
            }
            
            //发放20%的直推奖励 的 KR
            $zhitui = bcmul(bcdiv($money,3,10),2,8);
            $parent = MemberModel::where('id',$member['pid'])->find();
            //直推烧伤算法：上级level_id>当前会员level_id，发放直推奖 KR
            if($parent!=null&&$parent['level_id']>=$member['level_id']-1){//这里的member.level_id是外层函数升级过的，所以是大于等于-1
                UserMoneyLogModel::change($member['pid'],'KR',$zhitui,'Direct deduction matrix reward','','直推分红');
            }
            
            //$p_member =  MemberModel::getDetails($member['pid']);
            //MemberModel::where('id',$member['pid'])->update(['power'=>bcadd($p_member['power'],bcmul($usdt_money,0.3,8),4)]);
            //发放流动性算力
            UserMoneyLogModel::change($member['pid'],'LP',bcmul($usdt_money,0.3,8),'Direct deduction matrix reward','','直推分红');
        // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
        }
    }

    /**
     * 授权兑换
     * @param $mid  用户ID
     */
    public static function authorized_redemption($mid){


        return true;
    }
    
    
    //计划任务 - 打入底池5% USDT0
    public static function network(){
        $info = TotalTimeModel::yesterday('SellKR');
        if(!empty($info)){
            $info = $info->toArray();
            if($info['total_num'] <= 0){
                echo '执行完成,没有USDT';
                die;
            }
            $headers = [
                'headers' => [
                    'accept'=>'application/json',
                    'content-type'=>'application/json',
                    'sign'  =>  md5(env('HEADER_SIGN').'amount:'.$info['total_num']),
                ]
            ];
            //请求数据
            $options = [
                'form_params'   =>  ['amount'=>$info['total_num']],
            ];
            $client = new \GuzzleHttp\Client($headers);
            $response = $client->request('POST', env('HEYUEURL_EMPOWER').'buyKRToken', $options);
            $response_data = json_decode($response->getBody(),true);
            if(is_array($response_data)){
                if($response_data['code'] == 1){
                    echo '执行完成';
                }else{
                    echo '执行失败';
                    var_export($response_data);
                }
                die;
            }else{
                echo '执行失败';
                die;
            }
        }
    }

}